윈도우 창 제목 변경 프로그램 (Window Title Manager, AutoHotkey v2)
목차
지금 실행 중인 창의 목록을 보여주고, 그중 하나를 골라 창 제목(타이틀바에 보이는 글자)을 원하는 이름으로 바꿔 주는 작은 프로그램의 코드를 공개하는 글입니다. AutoHotkey v2로 만들었고, AI와 함께 작업하며 다듬었습니다.
같은 프로그램 창을 여러 개 띄워 놓고 구분하고 싶을 때(예: 같은 이름의 창 여러 개에 D1, D2처럼 이름 붙이기),
또는 작업표시줄·캡처 화면에서 창 이름을 알아보기 쉽게 바꾸고 싶을 때 쓸 수 있습니다.
이 글의 구성 방침: 실행에 필요한 폴더 구조와 소스 파일을 빠짐없이 올렸습니다. 각 파일은 오른쪽 목차에서 클릭해서 바로 이동할 수 있습니다. 백업본(
.bak,.OLD)과 실행 중 저장되는 기록 파일(TitleHistory.txt)은 본문에서 뺐습니다.
🟡 프로젝트 소개 #
🟡 어떤 프로그램인가 #
- 열려 있는 창을 창 제목 · 프로세스 · HWND 세 칸으로 목록에 보여줍니다. 1초마다 자동으로 갱신됩니다.
- 새로 뜬 창은 목록 맨 위에 올라오고(프로세스가 가장 늦게 시작된 창이 위), 닫힌 창은 목록에서 사라집니다. 바뀐 부분만 반영해서 깜빡임과 선택 해제가 없습니다.
- 목록에서 창을 더블클릭하거나 [제목 변경] 버튼을 누르면 새 제목 입력창이 뜹니다.
- 입력창 아래에는 최근 사용한 제목 20개가 나오고, 하나를 더블클릭하면 바로 적용됩니다. 기록은
TitleHistory.txt에 저장되어 프로그램을 껐다 켜도 남습니다. - 이 프로그램 자신의 창과 화면에 보이지 않는 유령 창(UWP 숨김 창), 바탕화면(
Program Manager)은 목록에서 제외합니다.
🟡 사용 방법 #
- AutoHotkey v2를 설치합니다. (
#Requires AutoHotkey v2.0) - 아래 폴더 구조대로 파일을 두고
Main.ahk를 실행합니다. - 목록에서 제목을 바꿀 창을 더블클릭하고, 새 제목을 입력한 뒤 확인을 누릅니다.
- 종료는 [종료] 버튼이나 창의 X 버튼입니다.
대상 프로그램이 관리자 권한으로 실행 중이면 제목 변경이 실패합니다. 이때는 이 스크립트도 관리자 권한으로 실행해야 합니다. (실패하면 프로그램이 같은 안내 메시지를 띄웁니다.)
🟡 폴더 구조 #
script/
├─ Classes/
│ ├─ Monitor.ahk # 특정 프로그램 창 제목을 유지하려던 클래스 (미완성, 현재 미사용)
│ ├─ Monitor.ahk.bak # [본문 제외] 백업본
│ ├─ TitleChanger.ahk # 제목 변경 + 원본 제목 저장·복원
│ ├─ TitleChanger.ahk.bak # [본문 제외] 백업본
│ ├─ WinAPI.ahk # Windows API 호출 모음 (제목 읽기·쓰기, PID, 클래스명 등)
│ ├─ WinAPI.ahk.bak # [본문 제외] 백업본
│ ├─ WindowManager.ahk # 창 목록 수집·검색 (현재 미사용)
│ ├─ WindowManager.ahk.bak # [본문 제외] 백업본
│ ├─ WindowSelector.ahk # 메인 화면 (창 목록 · 제목 입력창 · 기록 파일)
│ └─ WindowSelector.ahk.bak # [본문 제외] 백업본
├─ Main.ahk # 시작 파일 (창 하나 띄우고 계속 실행)
├─ Main.ahk,bak # [본문 제외] 백업본
├─ Main.ahk.OLD # [본문 제외] 백업본
├─ TitleHistory.txt # [본문 제외] 실행 중 저장되는 기록
├─ winex.ps1 # 로그온/시작 시 실행되는 작업 스케줄러 항목 조회
├─ wintest.ps1 # 시작 프로그램·서비스 종합 점검 (조회 전용)
└─ wintestSC.bat # wintest.ps1을 실행하는 배치 파일
🟡 동작 구조 #
Main.ahk
└─ WindowSelector.Show() 메인 창 · 1초 타이머로 목록 갱신 · 제목 입력창 · 기록 파일
├─ WinAPI 제목 읽기(GetWindowTextW) · 프로세스 ID · 클래스명 등 Windows API 호출
└─ TitleChanger 제목 변경(SetWindowTextW) + 처음 제목 저장/복원
TitleChanger에는 원래 제목으로 되돌리는 Restore, RestoreAll 함수도 들어 있지만, 현재 화면에서는 아직 연결하지 않았습니다.
복사해서 쓸 때 주의: 코드 안의 한글(주석과 화면 문구)이 깨지지 않게 파일은 UTF-8(BOM 포함) 으로 저장하세요. AutoHotkey v2는 BOM이 없는 파일을 UTF-8로 읽습니다.
🟣 진입점 — 시작 파일 #
🟣 Main.ahk — 시작 파일 (창 하나 띄우고 계속 실행) #
#Requires AutoHotkey v2.0
#SingleInstance Force
#Include Classes\WinAPI.ahk
#Include Classes\TitleChanger.ahk
#Include Classes\WindowSelector.ahk
; 창을 띄우고 계속 실행 (종료 버튼 또는 창 닫기(X)로 종료)
WindowSelector.Show()
🔴 Classes — 핵심 코드 #
🔴 Classes/WindowSelector.ahk — 메인 화면 (창 목록 · 제목 입력창 · 기록 파일) #
class WindowSelector
{
static MainGui := ""
static LV := ""
static Status := ""
static BtnChange := ""
static BtnRefresh := ""
static BtnExit := ""
static LastSnap := ""
; 변경했던 제목 기록 (Main.ahk와 같은 폴더, 최근 것이 위)
static HistoryFile := A_ScriptDir "\TitleHistory.txt"
static HistoryMax := 20
;==================================================
; 메인 창 표시 (상시 실행)
;==================================================
static Show()
{
g := Gui("+Resize +MinSize560x300", "Window Title Manager")
g.SetFont("s10", "맑은 고딕")
this.MainGui := g
g.AddText("w700", "제목을 바꿀 창을 선택 후 더블클릭 (또는 [제목 변경] 버튼)")
this.LV := g.AddListView("w700 h320 Grid -Multi NoSort", ["창 제목", "프로세스", "HWND"])
this.LV.ModifyCol(1, 400)
this.LV.ModifyCol(2, 160)
this.LV.ModifyCol(3, 100)
this.BtnChange := g.AddButton("w110 h30", "제목 변경")
this.BtnRefresh := g.AddButton("x+10 w110 h30", "새로고침")
this.BtnExit := g.AddButton("x+10 w110 h30", "종료")
this.Status := g.AddText("x+20 yp w250 h30 0x200", "")
this.LV.OnEvent("DoubleClick", ObjBindMethod(this, "ChangeSelected"))
this.BtnChange.OnEvent("Click", ObjBindMethod(this, "ChangeSelected"))
this.BtnRefresh.OnEvent("Click", ObjBindMethod(this, "Refresh", true))
this.BtnExit.OnEvent("Click", (*) => ExitApp())
g.OnEvent("Size", ObjBindMethod(this, "OnSize"))
g.OnEvent("Close", (*) => ExitApp())
this.Refresh(true)
g.Show("w720 h440")
; 1초마다 자동 갱신 (새 창 실행/종료/제목 변경이 리스트에 반영됨)
SetTimer(ObjBindMethod(this, "Refresh"), 1000)
}
;==================================================
; 창 크기 변경 시 레이아웃 조정
;==================================================
static OnSize(guiObj, minMax, w, h)
{
if (minMax = -1)
return
this.LV.Move(, , w - 20, h - 100)
this.BtnChange.Move(, h - 45)
this.BtnRefresh.Move(, h - 45)
this.BtnExit.Move(, h - 45)
this.Status.Move(, h - 45)
}
;==================================================
; 창 리스트 갱신 (변경된 부분만 반영 -> 깜빡임/선택 해제 없음)
;==================================================
static Refresh(force := false, *)
{
cur := Map()
myPid := DllCall("GetCurrentProcessId", "uint")
for hwnd in WinGetList()
{
title := WinAPI.GetTitle(hwnd)
if (title = "" || title = "Program Manager")
continue
if this.IsCloaked(hwnd)
continue
try
{
pid := WinGetPID(hwnd)
}
catch
{
continue
}
; 이 프로그램 자신의 창은 제외
if (pid = myPid)
continue
try
{
exe := WinGetProcessName(hwnd)
}
catch
{
exe := ""
}
cur[hwnd] := [title, exe, pid]
}
; 이전과 똑같으면 아무것도 안 함
snap := ""
for hwnd, info in cur
snap .= hwnd "|" info[1] "|" info[2] "`n"
if (!force && snap = this.LastSnap)
return
this.LastSnap := snap
lv := this.LV
lv.Opt("-Redraw")
; 1) 기존 행: 사라진 창은 삭제, 제목/프로세스가 바뀐 창은 수정
seen := Map()
row := lv.GetCount()
while (row >= 1)
{
h := Integer(lv.GetText(row, 3))
if !cur.Has(h)
{
lv.Delete(row)
}
else
{
info := cur[h]
if (lv.GetText(row, 1) != info[1] || lv.GetText(row, 2) != info[2])
lv.Modify(row, "", info[1], info[2])
seen[h] := true
}
row--
}
; 2) 새로 생긴 창은 맨 위에 추가 (프로세스 시작 시각 오름차순으로 위에 쌓음
; -> 같은 순간에 여러 개가 떠도 가장 최근에 실행된 것이 맨 위)
lines := ""
for h, info in cur
{
if !seen.Has(h)
lines .= Format("{:020d}", this.StartTime(info[3])) "|" h "`n"
}
if (lines != "")
{
lines := Sort(Trim(lines, "`n"))
Loop Parse, lines, "`n"
{
parts := StrSplit(A_LoopField, "|")
h := Integer(parts[2])
info := cur[h]
lv.Insert(1, "", info[1], info[2], h)
}
}
lv.Opt("+Redraw")
this.Status.Text := "창 " lv.GetCount() "개 (1초마다 자동 갱신)"
}
;==================================================
; 프로세스 시작 시각 (FILETIME 정수, 못 얻으면 0)
;==================================================
static StartTime(pid)
{
hProc := DllCall("OpenProcess"
, "uint", 0x1000
, "int", 0
, "uint", pid
, "ptr")
if !hProc
return 0
buf := Buffer(32, 0)
ok := DllCall("GetProcessTimes"
, "ptr", hProc
, "ptr", buf.Ptr
, "ptr", buf.Ptr + 8
, "ptr", buf.Ptr + 16
, "ptr", buf.Ptr + 24
, "int")
DllCall("CloseHandle", "ptr", hProc)
return ok ? NumGet(buf, 0, "int64") : 0
}
;==================================================
; DWM에 의해 숨겨진(cloaked) 창인지 확인 (UWP 유령 창 제외용)
;==================================================
static IsCloaked(hwnd)
{
cloaked := 0
hr := DllCall("dwmapi\DwmGetWindowAttribute"
, "ptr", hwnd
, "uint", 14
, "uint*", &cloaked
, "uint", 4
, "int")
return (hr = 0 && cloaked != 0)
}
;==================================================
; 선택한 창의 제목 변경 시작 (더블클릭 / 버튼 공용)
;==================================================
static ChangeSelected(*)
{
row := this.LV.GetNext()
if !row
{
MsgBox("먼저 창을 선택하세요.", "Title 변경", "Owner" this.MainGui.Hwnd)
return
}
hwnd := Integer(this.LV.GetText(row, 3))
this.AskTitle(hwnd)
}
;==================================================
; 새 제목 입력창 (메인 창은 그대로 유지)
;==================================================
static AskTitle(hwnd)
{
if !WinAPI.IsWindow(hwnd)
{
MsgBox("이 창은 이미 닫혔습니다.", "Title 변경", "Owner" this.MainGui.Hwnd)
this.Refresh(true)
return
}
history := this.LoadHistory()
dlg := Gui("+Owner" this.MainGui.Hwnd, "Title 변경")
dlg.SetFont("s10", "맑은 고딕")
dlg.AddText("w460", "새로운 제목 입력")
edit := dlg.AddEdit("w460", WinAPI.GetTitle(hwnd))
if (history.Length > 0)
{
dlg.AddText("w460", "최근 사용한 제목 (더블클릭하면 바로 적용)")
lb := dlg.AddListBox("w460 r10", history)
lb.OnEvent("Change", ObjBindMethod(this, "PickHistory", edit))
lb.OnEvent("DoubleClick", ObjBindMethod(this, "PickAndApply", dlg, edit, hwnd))
}
btnOk := dlg.AddButton("Default w100", "확인")
btnCan := dlg.AddButton("x+10 w100", "취소")
btnOk.OnEvent("Click", ObjBindMethod(this, "ApplyTitle", dlg, edit, hwnd))
btnCan.OnEvent("Click", ObjBindMethod(this, "CloseDialog", dlg))
dlg.OnEvent("Close", ObjBindMethod(this, "CloseDialog", dlg))
dlg.OnEvent("Escape", ObjBindMethod(this, "CloseDialog", dlg))
; 입력창이 떠 있는 동안 메인 창 조작 잠금
this.MainGui.Opt("+Disabled")
dlg.Show()
edit.Focus()
}
;==================================================
; 확인 버튼: 제목 적용
;==================================================
static ApplyTitle(dlg, edit, hwnd, *)
{
newTitle := edit.Value
this.CloseDialog(dlg)
if (newTitle != "")
{
if !TitleChanger.SetTitle(hwnd, newTitle)
{
MsgBox(
"제목 변경에 실패했습니다.`n`n"
"대상이 관리자 권한으로 실행 중인 프로그램이면`n"
"이 스크립트도 관리자 권한으로 실행해야 합니다.",
"Title 변경",
"Owner" this.MainGui.Hwnd
)
}
else
{
this.SaveHistory(newTitle)
}
}
this.Refresh(true)
}
;==================================================
; 입력창 닫기 (메인 창 잠금 해제 후 제거)
;==================================================
static CloseDialog(dlg, *)
{
this.MainGui.Opt("-Disabled")
dlg.Destroy()
}
;==================================================
; 기록 리스트에서 선택 -> 입력칸에 채우기
;==================================================
static PickHistory(edit, lb, *)
{
if (lb.Text != "")
edit.Value := lb.Text
}
;==================================================
; 기록 리스트에서 더블클릭 -> 바로 적용
;==================================================
static PickAndApply(dlg, edit, hwnd, lb, *)
{
if (lb.Text = "")
return
edit.Value := lb.Text
this.ApplyTitle(dlg, edit, hwnd)
}
;==================================================
; 기록 파일 읽기 (한 줄에 제목 하나, 최근 것이 위)
;==================================================
static LoadHistory()
{
list := []
if !FileExist(this.HistoryFile)
return list
try
{
text := FileRead(this.HistoryFile, "UTF-8")
}
catch
{
return list
}
for line in StrSplit(text, "`n", "`r")
{
if (line != "" && list.Length < this.HistoryMax)
list.Push(line)
}
return list
}
;==================================================
; 기록 파일에 저장 (중복은 맨 위로, 최대 20개)
;==================================================
static SaveHistory(title)
{
list := [title]
for t in this.LoadHistory()
{
if (t !== title && list.Length < this.HistoryMax)
list.Push(t)
}
text := ""
for t in list
text .= t "`r`n"
try
{
f := FileOpen(this.HistoryFile, "w", "UTF-8")
f.Write(text)
f.Close()
}
}
}
🔴 Classes/TitleChanger.ahk — 제목 변경 + 원본 제목 저장·복원 #
class TitleChanger
{
; 원본 제목 저장
static OriginalTitles := Map()
;==================================================
; 제목 변경
;==================================================
static SetTitle(hwnd, newTitle)
{
if !WinAPI.IsWindow(hwnd)
return false
; 최초 1회만 원본 저장
if !this.OriginalTitles.Has(hwnd)
{
oldTitle := WinAPI.GetTitle(hwnd)
this.OriginalTitles[hwnd] := oldTitle
}
return WinAPI.SetTitle(hwnd, newTitle)
}
;==================================================
; 원본 제목 복원
;==================================================
static Restore(hwnd)
{
if !this.OriginalTitles.Has(hwnd)
return false
oldTitle := this.OriginalTitles[hwnd]
result := WinAPI.SetTitle(hwnd, oldTitle)
if result
{
this.OriginalTitles.Delete(hwnd)
}
return result
}
;==================================================
; 모든 창 복원
;==================================================
static RestoreAll()
{
for hwnd, oldTitle in this.OriginalTitles
{
if WinAPI.IsWindow(hwnd)
{
WinAPI.SetTitle(hwnd, oldTitle)
}
}
this.OriginalTitles.Clear()
}
;==================================================
; 저장된 원본 제목 가져오기
;==================================================
static GetOriginal(hwnd)
{
if this.OriginalTitles.Has(hwnd)
return this.OriginalTitles[hwnd]
return ""
}
;==================================================
; 변경 여부 확인
;==================================================
static IsChanged(hwnd)
{
return this.OriginalTitles.Has(hwnd)
}
;==================================================
; 저장 정보 삭제
;==================================================
static Remove(hwnd)
{
if this.OriginalTitles.Has(hwnd)
this.OriginalTitles.Delete(hwnd)
}
}
🔴 Classes/WinAPI.ahk — Windows API 호출 모음 (제목 읽기·쓰기, PID, 클래스명 등) #
class WinAPI
{
;--------------------------------------------------
; HWND의 현재 제목 얻기
;--------------------------------------------------
static GetTitle(hwnd)
{
len := DllCall("GetWindowTextLengthW"
, "ptr", hwnd
, "int")
buf := Buffer((len + 1) * 2)
DllCall("GetWindowTextW"
, "ptr", hwnd
, "ptr", buf.Ptr
, "int", len + 1)
return StrGet(buf)
}
;--------------------------------------------------
; 제목 변경
;--------------------------------------------------
static SetTitle(hwnd, title)
{
result := DllCall(
"SetWindowTextW",
"ptr", hwnd,
"str", title,
"int"
)
Return result
}
;--------------------------------------------------
; 창 존재 여부
;--------------------------------------------------
static IsWindow(hwnd)
{
return DllCall("IsWindow"
, "ptr", hwnd
, "int")
}
;--------------------------------------------------
; 창 표시 여부
;--------------------------------------------------
static IsVisible(hwnd)
{
return DllCall("IsWindowVisible"
, "ptr", hwnd
, "int")
}
;--------------------------------------------------
; 프로세스 ID 얻기
;--------------------------------------------------
static GetPID(hwnd)
{
pid := 0
DllCall("GetWindowThreadProcessId"
, "ptr", hwnd
, "uint*", &pid)
return pid
}
;--------------------------------------------------
; 프로세스 이름
;--------------------------------------------------
static GetProcessName(hwnd)
{
try
{
pid := this.GetPID(hwnd)
return ProcessGetName(pid)
}
catch
{
return ""
}
}
;--------------------------------------------------
; 클래스명
;--------------------------------------------------
static GetClass(hwnd)
{
buf := Buffer(512)
DllCall("GetClassNameW"
, "ptr", hwnd
, "ptr", buf.Ptr
, "int", 256)
return StrGet(buf)
}
}
🔵 Classes — 현재 사용하지 않는 클래스 #
Main.ahk가 불러오지 않는 파일들입니다. 이전 시도의 코드이고, 특히 Monitor.ahk는 미완성 상태입니다.
🔵 Classes/WindowManager.ahk — 창 목록 수집·검색 (현재 미사용) #
class WindowManager
{
static List := Map()
;==================================================
; 모든 창 검색
;==================================================
static Refresh()
{
this.List.Clear()
cb := CallbackCreate(EnumWindowsProc)
DllCall("EnumWindows"
, "ptr", cb
, "ptr", 0)
CallbackFree(cb)
}
;==================================================
; HWND로 정보 가져오기
;==================================================
static Get(hwnd)
{
if this.List.Has(hwnd)
return this.List[hwnd]
return false
}
;==================================================
; HWND 존재 여부
;==================================================
static Exists(hwnd)
{
return this.List.Has(hwnd)
}
;==================================================
; 제목 검색
;==================================================
static FindByTitle(keyword)
{
result := []
for hwnd, info in this.List
{
if InStr(info["Title"], keyword)
result.Push(info)
}
return result
}
;==================================================
; 실행 파일 검색
;==================================================
static FindByExe(exe)
{
result := []
for hwnd, info in this.List
{
if (StrLower(info["Process"]) = StrLower(exe))
result.Push(info)
}
return result
}
;==================================================
; PID 검색
;==================================================
static FindByPID(pid)
{
for hwnd, info in this.List
{
if (info["PID"] = pid)
return info
}
return false
}
;==================================================
; Window Class 검색
;==================================================
static FindByClass(className)
{
result := []
for hwnd, info in this.List
{
if (info["Class"] = className)
result.Push(info)
}
return result
}
}
;======================================================
; EnumWindows Callback
;======================================================
EnumWindowsProc(hwnd, lParam)
{
if !WinAPI.IsWindow(hwnd)
return true
if !WinAPI.IsVisible(hwnd)
return true
title := WinAPI.GetTitle(hwnd)
if (title = "")
return true
; 바탕화면 제외
if (title = "Program Manager")
return true
info := Map()
info["HWND"] := hwnd
info["Title"] := title
info["PID"] := WinAPI.GetPID(hwnd)
info["Process"] := WinAPI.GetProcessName(hwnd)
info["Class"] := WinAPI.GetClass(hwnd)
WindowManager.List[hwnd] := info
return true
}
🔵 Classes/Monitor.ahk — 특정 프로그램 창 제목을 유지하려던 클래스 (미완성, 현재 미사용) #
class Monitor
{
static Targets := Map()
static ProcessTargets := Map()
__New()
{
this.ProcessTargets := Map(
"D2R.exe", "Diablo II: Resurrected"
)
this.Targets := Map()
}
;==================================================
; 프로세스 검사
;==================================================
static CheckProcess()
{
for exeName, wantedTitle in this.ProcessTargets
{
hwnd := WinExist("ahk_exe " exeName)
if hwnd
{
; 이미 등록되어 있으면 생략
if !this.Targets.Has(hwnd)
{
this.Targets[hwnd] := wantedTitle
; 새 창 발견
this.ShowWindow(hwnd, wantedTitle)
TitleChanger.SetTitle(hwnd, wantedTitle)
}
}
}
}
ShowWindow(hwnd, wantedTitle)
{
current := WinAPI.GetTitle(hwnd)
MsgBox(
"발견`n`n"
"HWND : " hwnd "`n"
"현재 제목 : " current "`n"
"변경 제목 : " wantedTitle
)
TitleChanger.SetTitle(hwnd, wantedTitle)
}
;==================================================
; 전체 검사
;==================================================
static Check()
{
this.CheckProcess()
for hwnd, wantedTitle in this.Targets
{
if !WinAPI.IsWindow(hwnd)
continue
; 현재 제목 확인
current := WinAPI.GetTitle(hwnd)
if (current != wantedTitle)
; 제목 변경 요청
TitleChanger.SetTitle(hwnd, wantedTitle)
}
}
}
🟢 부록 — 함께 있던 시작 프로그램 점검 스크립트 #
창 제목 프로그램과는 별개로 같은 폴더에 있던 PowerShell 스크립트입니다. 시작 시 자동 실행되는 항목을 조회만 하고 아무것도 바꾸지 않습니다. wintestSC.bat 안의 경로(C:\script\wintest.ps1)는 본인 환경에 맞게 고쳐서 쓰세요.
🟢 wintest.ps1 — 시작 프로그램·서비스 종합 점검 (조회 전용) #
Write-Host "==== [1] HKCU Run ====" -ForegroundColor Cyan
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" |
Select-Object *
Write-Host "`n==== [2] HKLM Run ====" -ForegroundColor Cyan
Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" |
Select-Object *
Write-Host "`n==== [3] Startup Folder (User) ====" -ForegroundColor Cyan
Get-ChildItem "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup"
Write-Host "`n==== [4] Startup Folder (All Users) ====" -ForegroundColor Cyan
Get-ChildItem "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup"
Write-Host "`n==== [5] Scheduled Tasks (Logon/Startup) ====" -ForegroundColor Cyan
Get-ScheduledTask | Where-Object {
$_.Triggers -match "AtLogOn|AtStartup"
} | Select-Object TaskName, TaskPath, State
Write-Host "`n==== [6] Automatic Services ====" -ForegroundColor Cyan
Get-Service | Where-Object {$_.StartType -eq "Automatic"} |
Select-Object Name, DisplayName, Status
🟢 winex.ps1 — 로그온/시작 시 실행되는 작업 스케줄러 항목 조회 #
Get-ScheduledTask |
Where-Object {
$_.Triggers -match "AtLogOn|AtStartup" -and
$_.TaskPath -notmatch "Microsoft"
} |
Select TaskName, TaskPath, State
🟢 wintestSC.bat — wintest.ps1을 실행하는 배치 파일 #
@echo off
powershell.exe -ExecutionPolicy Bypass -File "C:\script\wintest.ps1"
pause